﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace DetectApp.Display;

public class RingControl : ROIControl
{
    private readonly Canvas _canvas;
    private readonly List<Shape> _docEllipse = new();
    private Point _circleCenter;
    private double _circleRad;
    private int _docDiameter = 0;
    private double _initRadius = 50;
    private bool _isMove;
    private bool _isRotate;
    private bool _isSCale1;
    private bool _isSCale2;
    private bool _isSCale3;
    private bool _isSCale4;
    private Point _ringEndPoint1;
    private PathFigure _ringFigure;
    private Path _ringPath;
    private ArcSegment _ringSegment1;
    private LineSegment _ringSegment2;
    private ArcSegment _ringSegment3;
    private Point _ringStartPoint1;
    private double _startAngle;
    private Point _startPoint;
    private double _startTopLeft;
    private double _startTopUp;
    public RingControl(Canvas canvas, Color color)
    {
        
        _canvas = canvas;
        _canvas.MouseMove += Canvas_MouseMove;
        double startx = canvas.ActualWidth / 2 - _initRadius * K;
        double starty = canvas.ActualHeight / 2;
        _ringFigure = new()
        {
            StartPoint = new(startx, starty),
            IsClosed = true,
            IsFilled = true,
        };
        _ringSegment1 = new()
        {
            Point = new(startx + _initRadius * K * 2, starty),
            Size = new Size { Width = _initRadius * K, Height = _initRadius * K },
            IsLargeArc = true,
            SweepDirection = SweepDirection.Clockwise,
        };
        _ringSegment2 = new()
        {
            Point = new(startx - 10 + _initRadius * K * 2, starty)
        };
        _ringSegment3 = new()
        {
            Point = new(startx + 10, starty),
            Size = new Size { Width = _initRadius * K - 10, Height = _initRadius * K - 10 },
            IsLargeArc = true,
            SweepDirection = SweepDirection.Counterclockwise,
        };

        _ringFigure.Segments.Add(_ringSegment1);
        _ringFigure.Segments.Add(_ringSegment2);
        _ringFigure.Segments.Add(_ringSegment3);
        PathGeometry ringGeometry = new();
        ringGeometry.Figures.Add(_ringFigure);
        _ringPath = new()
        {
            Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.1 },
            Stroke = new SolidColorBrush(color),
            StrokeThickness = 0.1,
            Data = ringGeometry,
        };
        canvas.Children.Add(_ringPath);
        Canvas.SetLeft(_ringPath, 0);
        Canvas.SetTop(_ringPath, 0);

        _ringPath.MouseEnter += (s, e) => { UpdateEllipse(_ringPath, canvas); };
        _ringPath.MouseLeftButtonDown += RingPath_MouseLeftButtonDown;
        _circleCenter.X = canvas.ActualWidth / 2;
        _circleCenter.Y = canvas.ActualHeight / 2;
        ROIChange?.Invoke(this, EventArgs.Empty);
    }

    public RingControl(Canvas canvas, ROIParam param)
    {
        _canvas = canvas;
        _canvas.MouseMove += Canvas_MouseMove;
        double startx = param.ring_startX;
        double starty = param.ring_startY;
        _ringFigure = new()
        {
            StartPoint = new(startx, starty),
            IsClosed = true,
            IsFilled = true,
        };
        _ringSegment1 = new()
        {
            Point = new(param.ring_pointx1, param.ring_pointy1),
            Size = new Size { Width = param.ring_width1, Height = param.ring_height1 },
            IsLargeArc = param.ring_IsLarge1,
            SweepDirection = param.ring_sweepDirection1,
        };
        _ringSegment2 = new()
        {
            Point = new(param.ring_pointx2, param.ring_pointy2)
        };
        _ringSegment3 = new()
        {
            Point = new(param.ring_pointx3, param.ring_pointy3),
            Size = new Size { Width = param.ring_width2, Height = param.ring_height2 },
            IsLargeArc = param.ring_IsLarge3,
            SweepDirection = param.ring_sweepDirection3,
        };

        _ringFigure.Segments.Add(_ringSegment1);
        _ringFigure.Segments.Add(_ringSegment2);
        _ringFigure.Segments.Add(_ringSegment3);
        PathGeometry ringGeometry = new();
        ringGeometry.Figures.Add(_ringFigure);
        _ringPath = new()
        {
            Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.1 },
            Stroke = new SolidColorBrush(Colors.Red),
            StrokeThickness = 0.1,
            Data = ringGeometry,
        };
        canvas.Children.Add(_ringPath);
        Canvas.SetLeft(_ringPath, param.Left);
        Canvas.SetTop(_ringPath, param.Top);

        _ringPath.MouseEnter += (s, e) => { UpdateEllipse(_ringPath, canvas); };
        _ringPath.MouseLeftButtonDown += RingPath_MouseLeftButtonDown;
        _circleCenter.X = canvas.ActualWidth / 2;
        _circleCenter.Y = canvas.ActualHeight / 2;
        ROIChange?.Invoke(this, EventArgs.Empty);
    }

    public double K { get => _canvas.ActualWidth / 500.0; }
    public override ROIParam GetParam()
    {
        ROIParam param = new() { ROIType = ROIType.圆环 };
        param.ring_startX = _ringFigure.StartPoint.X;
        param.ring_startY = _ringFigure.StartPoint.Y;

        param.ring_pointx1 = _ringSegment1.Point.X;
        param.ring_pointy1 = _ringSegment1.Point.Y;

        param.ring_width1 = _ringSegment1.Size.Width;
        param.ring_height1 = _ringSegment1.Size.Height;
        param.ring_IsLarge1 = _ringSegment1.IsLargeArc;
        param.ring_sweepDirection1 = _ringSegment1.SweepDirection;
        param.ring_pointx2 = _ringSegment2.Point.X;
        param.ring_pointy2 = _ringSegment2.Point.Y;

        param.ring_pointx3 = _ringSegment3.Point.X;
        param.ring_pointy3 = _ringSegment3.Point.Y;
        param.ring_width2 = _ringSegment3.Size.Width;
        param.ring_height2 = _ringSegment3.Size.Height;
        param.ring_IsLarge3 = _ringSegment3.IsLargeArc;
        param.ring_sweepDirection3 = _ringSegment3.SweepDirection;

        param.Left = Canvas.GetLeft(_ringPath);
        param.Top = Canvas.GetTop(_ringPath);
        return param;
    }

    public override HRegion? GetRegion()
    {
        double rad1 = _ringSegment1.Size.Width; //半径1
        double rad2 = _ringSegment3.Size.Width;
        double startAngle = Math.Atan2(_ringSegment1.Point.Y - _circleCenter.Y, _ringSegment1.Point.X - _circleCenter.X);
        double endAngle = Math.Atan2(_ringFigure.StartPoint.Y - _circleCenter.Y, _ringFigure.StartPoint.X - _circleCenter.X);
        Point center = _ringPath.TranslatePoint(_circleCenter, _canvas);
        HRegion region1 = new();
        if (startAngle > 0)
        {
            startAngle = Math.PI * 2 - startAngle;
        }
        else
        {
            startAngle *= -1;
        }
        if (endAngle > 0)
        {
            endAngle = Math.PI * 2 - endAngle;
        }
        else endAngle *= -1;
        region1.GenCircleSector(center.Y, center.X, rad1, startAngle, endAngle);

        HRegion region2 = new();

        region2.GenCircleSector(center.Y, center.X, rad2, startAngle, endAngle);
        return region1.Difference(region2);
    }

    public override ROIInfo GetROI()
    {
        ROIInfo roi = new() { ROIType = ROIType.无 };
        double startAngle = Math.Atan2(_ringSegment1.Point.Y - _circleCenter.Y, _ringSegment1.Point.X - _circleCenter.X);
        double endAngle = Math.Atan2(_ringFigure.StartPoint.Y - _circleCenter.Y, _ringFigure.StartPoint.X - _circleCenter.X);
        if (startAngle > 0)
        {
            startAngle = Math.PI * 2 - startAngle;
        }
        else
        {
            startAngle *= -1;
        }
        if (endAngle > 0)
        {
            endAngle = Math.PI * 2 - endAngle;
        }
        else endAngle *= -1;
        Point center = _ringPath.TranslatePoint(_circleCenter, _canvas);
        double rad1 = _ringSegment1.Size.Width; //半径1
        double rad2 = _ringSegment3.Size.Width;
        double rad = (rad1 + rad2) / 2;

        roi.ROIType = ROIType.圆环;
        roi.RingStartAngle = startAngle;
        roi.RingEndAngle = endAngle;
        roi.RingRadius = rad;
        roi.RingCenter = center;
        roi.RingWidth = rad1 - rad2;
        return roi;
    }

    public override void Remove()
    {
        _canvas.Children.Remove(_ringPath);
    }

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (Mouse.LeftButton == MouseButtonState.Released)
        {
            _isMove = false; _isSCale1 = false; _isSCale2 = false; _isSCale3 = false; _isSCale4 = false; _isRotate = false;
        }
        if (!_isSCale1 & !_isSCale2 & !_isSCale3 & !_isSCale4 & !_isMove & !_isRotate)
        {
            bool isClear = true;
            if (_ringPath.IsMouseOver == true) { isClear = false; }
            foreach (var rect in _docEllipse)
            {
                if (rect.IsMouseOver)
                {
                    isClear = false;
                    break;
                }
            }
            if (isClear)
            {
                _docEllipse.ForEach(e => { _canvas.Children.Remove(e); });
                _docEllipse.Clear();
            };
        }
        if (_isMove)
        {
            Point curPoint = Mouse.GetPosition(_canvas);
            var rPoint = curPoint - _startPoint;
            Canvas.SetLeft(_ringPath, _startTopLeft + rPoint.X);
            Canvas.SetTop(_ringPath, _startTopUp + rPoint.Y);
            UpdateEllipse(_ringPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale1)
        {
            Point endPoint = Mouse.GetPosition(_ringPath);
            HOperatorSet.DistancePp(_circleCenter.Y, _circleCenter.X, endPoint.Y, endPoint.X, out HTuple distance);
            _ringSegment1.Size = new Size() { Width = distance, Height = distance };
            double rb = (distance) / _circleRad;
            _ringFigure.StartPoint = new Point((_ringStartPoint1.X - _circleCenter.X) * rb + _circleCenter.X, (_ringStartPoint1.Y - _circleCenter.Y) * rb + _circleCenter.Y);
            _ringSegment1.Point = new Point((_ringEndPoint1.X - _circleCenter.X) * rb + _circleCenter.X, (_ringEndPoint1.Y - _circleCenter.Y) * rb + _circleCenter.Y);
            UpdateEllipse(_ringPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale2)
        {
            Point endPoint = Mouse.GetPosition(_ringPath);
            HOperatorSet.DistancePp(_circleCenter.Y, _circleCenter.X, endPoint.Y, endPoint.X, out HTuple distance);
            _ringSegment3.Size = new Size() { Width = distance, Height = distance };
            double rb = (distance) / _circleRad;
            _ringSegment3.Point = new Point((_ringStartPoint1.X - _circleCenter.X) * rb + _circleCenter.X, (_ringStartPoint1.Y - _circleCenter.Y) * rb + _circleCenter.Y);
            _ringSegment2.Point = new Point((_ringEndPoint1.X - _circleCenter.X) * rb + _circleCenter.X, (_ringEndPoint1.Y - _circleCenter.Y) * rb + _circleCenter.Y);

            UpdateEllipse(_ringPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale3)
        {
            Point endPoint = Mouse.GetPosition(_ringPath);
            double angle = Math.Atan2(endPoint.Y - _circleCenter.Y, endPoint.X - _circleCenter.X);
            double ra = angle - _startAngle;
            double x = (_ringStartPoint1.X - _circleCenter.X) * Math.Cos(ra) - (_ringStartPoint1.Y - _circleCenter.Y) * Math.Sin(ra) + _circleCenter.X;
            double y = (_ringStartPoint1.X - _circleCenter.X) * Math.Sin(ra) + (_ringStartPoint1.Y - _circleCenter.Y) * Math.Cos(ra) + _circleCenter.Y;
            _ringFigure.StartPoint = new Point(x, y);
            HOperatorSet.AngleLl(y, x, _circleCenter.Y, _circleCenter.X, _ringSegment1.Point.Y, _ringSegment1.Point.X, _circleCenter.Y, _circleCenter.X, out HTuple angle1);
            if (angle1 > 0)
                _ringSegment1.IsLargeArc = true;
            else _ringSegment1.IsLargeArc = false;

            x = (_ringEndPoint1.X - _circleCenter.X) * Math.Cos(ra) - (_ringEndPoint1.Y - _circleCenter.Y) * Math.Sin(ra) + _circleCenter.X;
            y = (_ringEndPoint1.X - _circleCenter.X) * Math.Sin(ra) + (_ringEndPoint1.Y - _circleCenter.Y) * Math.Cos(ra) + _circleCenter.Y;
            _ringSegment3.Point = new Point(x, y);
            HOperatorSet.AngleLl(y, x, _circleCenter.Y, _circleCenter.X, _ringSegment2.Point.Y, _ringSegment2.Point.X, _circleCenter.Y, _circleCenter.X, out HTuple angle2);
            if (angle2 > 0)
                _ringSegment3.IsLargeArc = true;
            else _ringSegment3.IsLargeArc = false;
            UpdateEllipse(_ringPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale4)
        {
            Point endPoint = Mouse.GetPosition(_ringPath);
            double angle = Math.Atan2(endPoint.Y - _circleCenter.Y, endPoint.X - _circleCenter.X);
            double ra = angle - _startAngle;
            double x = (_ringStartPoint1.X - _circleCenter.X) * Math.Cos(ra) - (_ringStartPoint1.Y - _circleCenter.Y) * Math.Sin(ra) + _circleCenter.X;
            double y = (_ringStartPoint1.X - _circleCenter.X) * Math.Sin(ra) + (_ringStartPoint1.Y - _circleCenter.Y) * Math.Cos(ra) + _circleCenter.Y;
            _ringSegment1.Point = new Point(x, y);
            HOperatorSet.AngleLl(y, x, _circleCenter.Y, _circleCenter.X, _ringFigure.StartPoint.Y, _ringFigure.StartPoint.X, _circleCenter.Y, _circleCenter.X, out HTuple angle1);
            if (angle1 < 0)
                _ringSegment1.IsLargeArc = true;
            else _ringSegment1.IsLargeArc = false;

            x = (_ringEndPoint1.X - _circleCenter.X) * Math.Cos(ra) - (_ringEndPoint1.Y - _circleCenter.Y) * Math.Sin(ra) + _circleCenter.X;
            y = (_ringEndPoint1.X - _circleCenter.X) * Math.Sin(ra) + (_ringEndPoint1.Y - _circleCenter.Y) * Math.Cos(ra) + _circleCenter.Y;
            _ringSegment2.Point = new Point(x, y);
            HOperatorSet.AngleLl(y, x, _circleCenter.Y, _circleCenter.X, _ringSegment3.Point.Y, _ringSegment3.Point.X, _circleCenter.Y, _circleCenter.X, out HTuple angle2);
            if (angle2 < 0)
                _ringSegment3.IsLargeArc = true;
            else _ringSegment3.IsLargeArc = false;
            UpdateEllipse(_ringPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
    }

    private void RingPath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _isMove = true;
        _startPoint = Mouse.GetPosition(_canvas);
        _startTopUp = Canvas.GetTop(_ringPath);
        _startTopLeft = Canvas.GetLeft(_ringPath);
    }
    private void UpdateEllipse(Path path, Canvas canvas)
    {
        //ROIChange?.Invoke(this, EventArgs.Empty);
        _docDiameter = (int)(5 * K);
        Brush fillBrush = new SolidColorBrush(Colors.Blue);
        double opacityK = 1;
        _docEllipse.ForEach(e => { canvas.Children.Remove(e); });
        _docEllipse.Clear();

        HOperatorSet.AngleLl(_circleCenter.Y, _circleCenter.X, _ringFigure.StartPoint.Y, _ringFigure.StartPoint.X, _circleCenter.Y, _circleCenter.X, _ringSegment1.Point.Y, _ringSegment1.Point.X, out HTuple angle);
        if (_ringSegment1.IsLargeArc) { angle = angle - 2 * Math.PI; }
        double x = (_ringFigure.StartPoint.X - _circleCenter.X) * Math.Cos(-angle / 2) - (_ringFigure.StartPoint.Y - _circleCenter.Y) * Math.Sin(-angle / 2) + _circleCenter.X;
        double y = (_ringFigure.StartPoint.X - _circleCenter.X) * Math.Sin(-angle / 2) + (_ringFigure.StartPoint.Y - _circleCenter.Y) * Math.Cos(-angle / 2) + _circleCenter.Y;
        Point point = path.TranslatePoint(new Point(x, y), canvas);
        Ellipse circle1 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle1, point.X - _docDiameter / 2);
        Canvas.SetTop(circle1, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle1);
        _docEllipse.Add(circle1);
        circle1.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale1 = true;
            _startPoint = Mouse.GetPosition(canvas);
            _circleRad = _ringSegment1.Size.Width;
            _ringStartPoint1 = _ringFigure.StartPoint;
            _ringEndPoint1 = _ringSegment1.Point;
        };
        circle1.MouseLeftButtonUp += (s, e) =>
        {
            _isSCale1 = false;
        };

        HOperatorSet.AngleLl(_circleCenter.Y, _circleCenter.X, _ringSegment3.Point.Y, _ringSegment3.Point.X, _circleCenter.Y, _circleCenter.X, _ringSegment2.Point.Y, _ringSegment2.Point.X, out HTuple angle1);
        if (_ringSegment3.IsLargeArc) { angle1 = angle1 - 2 * Math.PI; }
        x = (_ringSegment3.Point.X - _circleCenter.X) * Math.Cos(-angle1 / 2) - (_ringSegment3.Point.Y - _circleCenter.Y) * Math.Sin(-angle1 / 2) + _circleCenter.X;
        y = (_ringSegment3.Point.X - _circleCenter.X) * Math.Sin(-angle1 / 2) + (_ringSegment3.Point.Y - _circleCenter.Y) * Math.Cos(-angle1 / 2) + _circleCenter.Y;
        point = path.TranslatePoint(new Point(x, y), canvas);
        Ellipse circle2 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle2, point.X - _docDiameter / 2);
        Canvas.SetTop(circle2, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle2);
        _docEllipse.Add(circle2);
        circle2.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale2 = true;
            _startPoint = Mouse.GetPosition(canvas);
            _circleRad = _ringSegment3.Size.Width;
            _ringStartPoint1 = _ringSegment3.Point;
            _ringEndPoint1 = _ringSegment2.Point;
        };
        circle2.MouseLeftButtonUp += (s, e) => { _isSCale2 = false; };

        point = path.TranslatePoint(new Point((_ringSegment3.Point.X - _ringFigure.StartPoint.X) / 2 + _ringFigure.StartPoint.X, (_ringSegment3.Point.Y - _ringFigure.StartPoint.Y) / 2 + _ringFigure.StartPoint.Y), canvas);
        Ellipse circle3 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle3, point.X - _docDiameter / 2);
        Canvas.SetTop(circle3, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle3);
        _docEllipse.Add(circle3);
        circle3.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale3 = true;
            _ringStartPoint1 = _ringFigure.StartPoint;
            _ringEndPoint1 = _ringSegment3.Point;
            _startAngle = Math.Atan2(_ringStartPoint1.Y - _circleCenter.Y, _ringStartPoint1.X - _circleCenter.X);
        };
        circle3.MouseLeftButtonUp += (s, e) => { _isSCale3 = false; };

        point = path.TranslatePoint(new Point((_ringSegment1.Point.X - _ringSegment2.Point.X) / 2 + _ringSegment2.Point.X, (_ringSegment1.Point.Y - _ringSegment2.Point.Y) / 2 + _ringSegment2.Point.Y), canvas);
        Ellipse circle4 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle4, point.X - _docDiameter / 2);
        Canvas.SetTop(circle4, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle4);
        _docEllipse.Add(circle4);
        circle4.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale4 = true;
            _ringStartPoint1 = _ringSegment1.Point;
            _ringEndPoint1 = _ringSegment2.Point;
            _startAngle = Math.Atan2(_ringSegment1.Point.Y - _circleCenter.Y, _ringSegment1.Point.X - _circleCenter.X);
        };
        circle4.MouseLeftButtonUp += (s, e) => { _isSCale4 = false; };
    }
}